#include <iostream>
#include <pthread.h>
#include <thread>
#include <unistd.h>
#include <vector>
#include "LockGuard.hpp"

using namespace std;

#define NUM 3

int ticket = 3000;

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

class threadData
{
public:
  threadData(int num, pthread_mutex_t *lock)
  {
    _name = "thread" + to_string(num);
    _lock = lock;
  }

public:
  string _name;
  pthread_mutex_t *_lock;
};

void *getTicket(void *args)
{
  threadData *td = static_cast<threadData *>(args);
  const char *name = td->_name.c_str();
  while (true)
  {
    {
      LockGurad lockguard(&lock);
      if (ticket > 0)
      {
        usleep(1000);
        printf("who = %s, get a ticket: %d\n", name, ticket);
        ticket--;
      }
      else
      {
        break;
      }
    }
    usleep(13);
  }
  return nullptr;
}

// void *getTicket(void *args)
// {
//   threadData *td = static_cast<threadData *>(args);
//   const char *name = td->_name.c_str();
//   while (true)
//   {
//     // pthread_mutex_lock(td->_lock);
//     pthread_mutex_lock(&lock);
//     if (ticket > 0)
//     {
//       usleep(100);
//       // cout << name << "get a ticket, ticket: " << ticket << endl;
//       printf("who = %s, get a ticket: %d\n", name, ticket);
//       // pthread_mutex_unlock(td->_lock);
//       pthread_mutex_unlock(&lock);
//       ticket--;
//     }
//     else
//     {
//       pthread_mutex_unlock(td->_lock);
//       break;
//     }
//   }
//   return nullptr;
// }

// 创建多线程，模拟抢票
int main()
{
  // pthread_mutex_t lock;
  // pthread_mutex_init(&lock, nullptr);

  vector<pthread_t> tids;
  vector<threadData *> tds;
  for (int i = 1; i <= NUM; i++)
  {
    pthread_t tid;
    threadData *td = new threadData(i, &lock);
    pthread_create(&tid, nullptr, getTicket, td);
    tids.push_back(tid);
    tds.push_back(td);
  }
  // 线程分离
  // sleep(1);
  // for (auto tid : tids)
  // {
  //   pthread_detach(tid);
  // }

  // 等待
  for (auto tid : tids)
  {
    pthread_join(tid, nullptr);
  }

  for (auto td : tds)
  {
    cout << td->_name << "is joining....." << endl;
    delete td;
  }

  // pthread_mutex_destroy(&lock);
  return 0;
}

// #define NUM 10

// int g_val = 0;

// class threadData
// {
// public:
//   threadData(int num)
//   {
//     _threadname = "thread" + to_string(num);
//   }

// public:
//   string _threadname;
// };

// void *threadRoutine(void *args)
// {
//   int test_i = 0;
//   threadData *td = static_cast<threadData *>(args);

//   while (true)
//   {
//     printf("pid: %d, threadname: %s, test_i: %d, &test_i: %p, g_val: %d, &g_val: %p\n", getpid(), td->_threadname.c_str(), test_i, &test_i, g_val, &g_val);
//     // cout << "pid:  " << getpid() << " threadname: " << td->_threadname << " test_i: " << test_i
//     //      << " &test_i: " << &test_i << " g_val: " << g_val << " &g_val: " << &g_val << endl;
//     g_val++;
//     test_i++;
//     sleep(1);
//   }

//   return nullptr;
// }

// // 每个线程有自己独立的栈结构
// int main()
// {
//   vector<pthread_t> tids;
//   for (int i = 0; i < NUM; i++)
//   {
//     pthread_t tid;
//     threadData *td = new threadData(i);

//     pthread_create(&tid, nullptr, threadRoutine, td);

//     tids.push_back(tid);
//   }

//   for (auto tid : tids)
//   {
//     pthread_join(tid, nullptr);
//   }

//   return 0;
// }

// #define NUM 3

// __thread int num = 0; // 让全局变量每个线程自动私有一份

// void *threadRoutine(void *args)
// {
//   // int test_i = 0; // 每个线程的上下文结构都不一样，并且都有自己独立的栈结构
//   string name = "thread" + to_string(*(int *)args);

//   int cnt = 0;
//   while (true)
//   {

//     cout << name << "is running...." << "num: " << num << " &num: " << &num << endl;
//     num++;

//     // int test_i = 0;
//     // cout << name << "is running...." << "test_i: " << test_i << " &test_i: " << &test_i << endl;
//     sleep(1);
//     // test_i++;
//     cnt++;
//     if (cnt > 20)
//       break;
//   }
//   return nullptr;
// }

// // 创建多线程
// int main()
// {
//   vector<pthread_t> tids;
// for (int i = 0; i < NUM; i++)
// {
//   pthread_t tid;
//   pthread_create(&tid, nullptr, threadRoutine, &i);
//   tids.push_back(tid);
// }

//   for (int i = 0; i < tids.size(); i++)
//   {
//     pthread_join(tids[i], nullptr);
//     cout << tids[i] << "is join......" << endl;
//   }

//   return 0;
// }

// string toHex(pthread_t tid)
// {
//   char hex[64];
//   snprintf(hex, sizeof(hex), "%p", tid);
//   return hex;
// }

// void *threadRoutine(void *args)
// {
//   const char *name = (const char *)args;
//   int cnt = 5;
//   while (true)
//   {
//     cout << name << "thread tid: " << toHex(pthread_self()) << endl;
//     sleep(1);
//     cnt--;
//     if (cnt == 0)
//       return nullptr;
//   }
// }

// int main()
// {
//   pthread_t tid;
//   pthread_create(&tid, nullptr, threadRoutine, (void *)"Thread 1");

//   cout << "new thread tid: " << toHex(tid) << endl;
//   pthread_join(tid, nullptr);

//   return 0;
// }

// void threadrun()
// {
//   while (true)
//   {
//     cout << "i am a new thread for c++" << endl;
//     sleep(1);
//   }
// }

// // c++11
// int main()
// {
//   thread t1(threadrun);

//   t1.join();

//   return 0;
// }

// class Request
// {
// public:
//   Request(int start, int end, const string &threadname)
//       : _start(start), _end(end), _threadname(threadname)
//   {
//   }

// public:
//   int _start;
//   int _end;
//   string _threadname;
// };

// class Respond
// {
// public:
//   Respond(int result, int exitcode)
//       : _result(result), _exitcode(exitcode)
//   {
//   }

// public:
//   int _result;
//   int _exitcode;
// };

// void *threadsum(void *args)
// {
//   Request *rq = static_cast<Request *>(args);
//   Respond *rsp = new Respond(0, 0);
//   for (int i = rq->_start; i <= rq->_end; i++)
//   {
//     cout << rq->_threadname << "is running , caling ...." << i << endl;
//     rsp->_result += i;
//     usleep(100000);
//   }
//   delete rq;
//   return rsp;
// }

// int main()
// {
//   pthread_t tid;

//   Request *rq = new Request(1, 100, "thread 1");

//   pthread_create(&tid, nullptr, threadsum, (void *)rq);

//   void *retval;
//   pthread_join(tid, &retval);

//   Respond *ret = static_cast<Respond *>(retval);

//   cout << "ret->_result:  " << ret->_result << " ret->_exitcode:  " << ret->_exitcode << endl;
//   delete ret;

//   return 0;
// }

// int g_val = 0;

// void show(const string &name)
// {
//   cout << name << "say@ " << "hello thread" << endl;
// }

// void *threadRoutine(void *args)
// {
//   int cnt = 5;
//   while (true)
//   {
//     const char *name = static_cast<char *>(args);
//     // cout << "i am a thread, pid: " << getpid() << endl;
//     // printf("%s pid: %d, g_val: %d, &g_val: %p\n", name, getpid(), g_val, &g_val);
//     sleep(1);
//     show("[new thread]");
//     cnt--;
//     if (cnt == 0)
//     {
//       break;
//     }
//   }
//   // return (void *)100; // 默认新的线程退出
//   pthread_exit((void *)1000);
// }

// int main()
// {
//   pthread_t tid;
//   pthread_create(&tid, nullptr, threadRoutine, (void *)"thread 1");

//   // void *retval;
//   // pthread_join(tid, &retval);

//   // cout << "pthread_join is successful, retval: " << (int)retval << endl;

//   int cnt = 5;
//   while (cnt--)
//   {
//     // cout << "major thread pid: " << getpid() << "g_val: " << g_val << "&g_val: " << &g_val << endl;
//     sleep(1);
//     show("[major thread]");
//     g_val++;
//   }
//   void *retval;
//   pthread_join(tid, &retval);
//   cout << "major process quit.... retval: " << (long long int)retval << endl;

//   return 0;
// }
